/*
 ============================================================================
 Name        : proc.c
 Author      : wy
 Version     :
 Copyright   : Your copyright notice
 Description : 协议处理
            head_low    head_high   len_l len_h ctrl    data    sum_check
              0xa5         0x5a       xx    xx   xx    xx...xx     xx
 ============================================================================
 */

#include "includes.h"

#define DEV_ID  "0535202012080001"  //4位区号+4位年+4位月日+4位顺序号

static int proc_makeAproc(uint8_t *pSrc,unsigned short len);
uint8_t proc_getProc(procChannelTypedef *procRBuf,uint16_t timeout);

static uint8_t proc_get_time(uint16_t timeout);
static uint8_t proc_online(uint16_t timeout);
static uint8_t proc_publish(uint16_t timeout);

static uint8_t tranBuf[PROC_MAX_LEN] = {0};

taskManageTypedef proc_tm;
procChannelTypedef procChan;

/*============================================================================
 协议初始化
 ============================================================================*/
static void proc_init()
{
    memset((void *)&proc_tm,0,sizeof(proc_tm));
    proc_tm.step = PROC_STEP_START;
    procChan.rb = &gprsRB;
    procChan.state = PROC_FIND_1ST_HEAD;
}

/*============================================================================
 协议任务
 初始化->上线->推送->结束
 ============================================================================*/
void proc_task()
{
    uint8_t res = FALSE;
    BaseType_t bit;
    uint8_t i;

#if (NET_MODULE == USE_ESP8266)
    while(1)
#endif
    {

    switch(proc_tm.step)
    {
        case PROC_STEP_START:
            proc_init();

#if (NET_MODULE == USE_ESP8266)

            ESP8266_BSP_INIT;
            //等待dht11和sgp30采样完成
            bit = xEventGroupWaitBits(os_eg_sampleCpl,eDht11Finishi | eSgp30Finishi,pdFALSE,pdTRUE,0);

            if((bit & (eDht11Finishi | eSgp30Finishi)) == (eDht11Finishi | eSgp30Finishi))
            {
                ESP8266_POWER_ON;
                DBG_PRT("ESP8266 power on!\n");
                
                osDelay(5000);

                for(i = 0;i < 3; i++)
                {
                    res = proc_get_time(5000);
                    if(res == TRUE)
                    {
                        break;
                    }
                }

                if(i < 3)
                {
                    proc_tm.step++;
                }
                
            }
                
#else
            proc_tm.step++;
#endif

            
            break;
        case PROC_STEP_ONLINE:
            res = proc_online(5000);
            if(res == TRUE)
            {
                DBG_PRT("proc_online get server response OK!\n");
                proc_tm.step++;
            }
            else
            {
                DBG_PRT("get server response ERR!\n");
                proc_tm.errCnt++;
            }
            break;
        case PROC_STEP_PUBLISH:
            res = proc_publish(5000);
            if(res == TRUE)
            {
                DBG_PRT("proc_publish get server response OK!\n");
                proc_tm.step++;
#if (NET_MODULE == USE_ESP8266)
                xEventGroupSetBits(os_eg_sampleCpl,ePublishFinishi);
                ESP8266_POWER_OFF;
                DBG_PRT("ESP8266 power off!\n");
#endif
            }
            else
            {
                DBG_PRT("get server response ERR!\n");
                proc_tm.errCnt++;
            }
            break;
        default:
            break;
    }

    }
}

/*============================================================================
 设备授时
 timeout：超时毫秒
 ============================================================================*/
static uint8_t proc_get_time(uint16_t timeout)
{
    uint8_t res = TRUE;
    uint16_t len_t = 4;

    memset(tranBuf,0,sizeof(tranBuf));
    tranBuf[len_t++] = 0xFE;
    
    len_t = proc_makeAproc(tranBuf,len_t - 4);
    
    if(gprs_bsp.write(tranBuf,len_t) == TRUE)
    {
        res = proc_getProc(&procChan,timeout);
        if(res == TRUE)
        {
            if(procChan.contentBuf[0] == 0xFE)
            {
                res = gprs_getTime(procChan.contentBuf + 1);
            }
            else
            {
                res = FALSE;
            }
        }
    }
    else
    {
        DBG_PRT("gprs write ERR!\n");
        res = FALSE;
    }
    
    return res;
}

/*============================================================================
 上线处理
 timeout：超时毫秒
 ============================================================================*/
static uint8_t proc_online(uint16_t timeout)
{
    uint8_t res = TRUE;
    uint16_t len_t = 4;
	uint32_t tick;

	tick = getUnixTick();
    memset(tranBuf,0,sizeof(tranBuf));
    tranBuf[len_t++] = 0x00;
    memcpy(tranBuf + len_t,(void *)&tick,4);
    len_t += 4;
    memcpy(tranBuf + len_t,DEV_ID,16);
    len_t += 16;
    
    len_t = proc_makeAproc(tranBuf,len_t - 4);
    
    if(gprs_bsp.write(tranBuf,len_t) == TRUE)
    {
        res = proc_getProc(&procChan,timeout);
        if(res == TRUE)
        {
            if(procChan.contentBuf[0] == 0x00)
            {
                res = TRUE;
            }
            else
            {
                res = FALSE;
            }
        }
    }
    else
    {
        DBG_PRT("gprs write ERR!\n");
        res = FALSE;
    }
    
    return res;
}

/*============================================================================
 推送采样数据
 timeout：超时毫秒
 ============================================================================*/
static uint8_t proc_publish(uint16_t timeout)
{
    uint8_t res = TRUE;
    uint16_t len_t = 4;
    SampleDataTypedef data;

    data.timeTick = getUnixTick();
    data.tempture = dht11Res.dht11_temp_avg;
    data.humidity = dht11Res.dht11_wet_avg;
    data.HCHO     = sgp30Res.tvoc_arg;
    data.CO2      = sgp30Res.co2_avg;
    data.cellVoltage = CellVoltage;

    memset(tranBuf,0,sizeof(tranBuf));
    tranBuf[len_t++] = 0x02;
    memcpy(tranBuf + len_t,(void *)&data.timeTick,4);
    len_t += 4;
    memcpy(tranBuf + len_t,DEV_ID,16);
    len_t += 16;
    memcpy(tranBuf + len_t,(void *)&data,sizeof(SampleDataTypedef));
    len_t += sizeof(SampleDataTypedef);
    
    len_t = proc_makeAproc(tranBuf,len_t - 4);
    
    if(gprs_bsp.write(tranBuf,len_t) == TRUE)
    {
        res = proc_getProc(&procChan,timeout);
        if(res == TRUE)
        {
            if(procChan.contentBuf[0] == 0x02)
            {
                res = TRUE;
            }
            else
            {
                res = FALSE;
            }
        }
    }
    else
    {
        DBG_PRT("gprs write ERR!\n");
        res = FALSE;
    }
    
    return res;
}

/*============================================================================
 重置搜报文状态机
 procRBuf：协议通道
 ============================================================================*/
static void rstProcState(procChannelTypedef *procRBuf)
{
    procRBuf->state = PROC_FIND_1ST_HEAD;
}

/*============================================================================
 搜报文
 procRBuf：协议通道
 timeout：超时毫秒
 ============================================================================*/
static uint8_t proc_getProc(procChannelTypedef *procRBuf,uint16_t timeout)
{
    int res = FALSE;
    int i;
    uint8_t byte;
    uint8_t sum = 0;
    uint32_t endTick = gprs_bsp.getTickMs() + timeout;

    while(1)
    {
        if(gprs_bsp.getTickMs() - endTick < 0xffffffff/2 || res == TRUE)
        {
            break;
        }

        if(procRBuf->rb->uart_idle_flag == 0)
        {
            gprs_bsp.dly_ms(100);
            continue;
        }

        procRBuf->rb->uart_idle_flag = 0;
        while(procRBuf->rb->pR - procRBuf->rb->pW != 0)
        {
            byte = procRBuf->rb->pRecvBuf[(procRBuf->rb->pR++) % GPRS_RECV_BUF_LEN];
            switch(procRBuf->state)
            {
                case PROC_FIND_1ST_HEAD:
                    if(byte == 0xa5)
                    {
                        procRBuf->state++;
                    }
                    break;
                case PROC_FIND_2ND_HEAD:
                    if(byte == 0x5a)
                    {
                        procRBuf->state++;
                        procRBuf->proclen  = 0;
                    }
                    else
                    {
                        rstProcState(procRBuf);
                    }
                    break;
                case PROC_GET_LEN_L:
                    procRBuf->proclen &= ~(0xff);
                    procRBuf->proclen |= byte;
                    procRBuf->state++;
                    break;
                case PROC_GET_LEN_H:
                    procRBuf->proclen &= ~(0xff00);
                    procRBuf->proclen |= (byte << 8);
                    if(procRBuf->proclen > GPRS_RECV_BUF_LEN)
                    {
                        rstProcState(procRBuf);
                    }
                    else
                    {
                        procRBuf->pWrite_contentBuf = 0;
                        procRBuf->state++;
                    }
                    break;
                case PROC_GET_DATA:
                    if(procRBuf->pWrite_contentBuf < procRBuf->proclen)
                    {
                        procRBuf->contentBuf[(procRBuf->pWrite_contentBuf) % GPRS_RECV_BUF_LEN] = byte;
                    }

                    if(++procRBuf->pWrite_contentBuf >= procRBuf->proclen)
                    {
                        procRBuf->state++;
                    }
                    break;
                case PROC_CHECK_SUM:
                    for(i = 0;i < procRBuf->proclen; i++)
                    {
                        sum += procRBuf->contentBuf[i];
                    }

                    if(sum == byte)
                    {
                        res = TRUE;
                    }

                    rstProcState(procRBuf);
                    break;
                default:
                    rstProcState(procRBuf);
                    break;
            }

            if(res == TRUE)
            {
                break;
            }
        }

    }

    return res;
}

/*============================================================================
 协议组包
 pSrc：报文缓存指针
 len：控制字+数据域长度
 return：此包报文总长度
 ============================================================================*/
static int proc_makeAproc(uint8_t *pSrc,unsigned short len)
{
    int i;
    int p = 0;
    uint8_t *pContent = pSrc + 4;
    uint8_t sum = 0;

    pSrc[p++] = 0xa5;
    pSrc[p++] = 0x5a;
    memcpy((void *)(pSrc + p),&len,2);
    p += 2;
    p += len;
    for(i = 0; i< len; i++)
    {
        sum += pContent[i];
    }
    pSrc[p] = sum;

    return (len + 2 + 2 + 1);
}


